package com.googlecode.pacswitch.conditions;

import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.SocketException;
import java.nio.channels.AsynchronousSocketChannel;
import java.util.Enumeration;

import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlType;

import com.googlecode.pacswitch.Condition;
import com.googlecode.pacswitch.ObjectFactory;
import com.googlecode.pacswitch.PString;
import com.googlecode.pacswitch.PacSwitch;
import com.googlecode.pacswitch.Utils;

/**
 * @author Andrey Pavlenko
 */
@XmlType(name = "LocalNet", namespace = ObjectFactory.CNS)
public class LocalNet implements Condition {
    private PString _address;
    private PString _mask;

    @XmlAttribute(required = true)
    public PString getAddress() {
        return _address;
    }

    public void setAddress(final PString address) {
        _address = address;
    }

    @XmlAttribute(required = true)
    public PString getMask() {
        return _mask;
    }

    public void setMask(final PString mask) {
        _mask = mask;
    }

    @Override
    public boolean apply(final PacSwitch ps,
            final AsynchronousSocketChannel clientSocket) {
        try {
            final int address = Utils.ipToInt(_address
                    .resolve(ps, clientSocket));
            final int mask = Utils.ipToInt(_mask.resolve(ps, clientSocket));
            final Enumeration<NetworkInterface> interfaces = NetworkInterface
                    .getNetworkInterfaces();

            while (interfaces.hasMoreElements()) {
                final Enumeration<InetAddress> addresses = interfaces
                        .nextElement().getInetAddresses();

                while (addresses.hasMoreElements()) {
                    final byte[] addr = addresses.nextElement().getAddress();
                    final int ip = (addr[3] & 0xFF) | ((addr[2] << 8) & 0xFF00)
                            | ((addr[1] << 16) & 0xFF0000)
                            | ((addr[0] << 24) & 0xFF000000);

                    if ((ip & mask) == address) {
                        return true;
                    }
                }
            }
        } catch (final SocketException ex) {
            ps.getConfig().getLog().error("Error occurred", ex);
        }

        return false;
    }
}
